/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package InstanciaJogo;

import Biblioteca.VerificacaoErros;
import DAO.DAOInstanciaJogo;
import DAO.MySQL.DAOInstanciaJogoMySQL;
import InstanciaJogo.FasesJogo.Estatica;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import GUI.Jogo.FrameJogo;
import javax.swing.ImageIcon;

/**
 * InstanciaJogoSwing
 *
 * Versao 1.0
 *
 * Data Criação 07/08/2013
 *
 * @author Igor
 */
public class InstanciaJogoSwing {

    //Atributos
    private long idJogo;
    private Estatica faseEstatica;
    private long fase;
    private long subFase;
    private int percAvancarSubFases;
    private Timer timerTransacaoImagem;
    private JLabel labelImagem;
    private JLabel labelStatus;
    private FrameJogo telaInicial;
    private int tempoApresentacaoImagens;
    private int tempoTransicaoImagens;
    private int repetirApresentacaoImagens;
    private boolean apresentaMensagemAcertoErro;
    private long modoJogo;

    //DAO
    private DAOInstanciaJogo jogoDAO;

    //Construtor
    public InstanciaJogoSwing() {
        this.fase = 1;
        this.subFase = 1; //Comeca-se sempre em 1, incrementa-se no iniciaFaseSubFase se necessario
        this.jogoDAO = new DAOInstanciaJogoMySQL();
    }

    public InstanciaJogoSwing(JLabel labelImagem, JLabel labelStatus, FrameJogo telaInicial) {
        this();
        this.labelImagem = labelImagem;
        this.labelStatus = labelStatus;
        this.telaInicial = telaInicial;
    }

    //Getters e Setters
    /**
     * @return the idJogo
     */
    public long getIdJogo() {
        return idJogo;
    }

    /**
     * @param idJogo the idJogo to set
     */
    public void setIdJogo(long idJogo) {
        this.idJogo = idJogo;
    }

    /**
     * @return the faseEstatica
     */
    public Estatica getFaseEstatica() {
        return faseEstatica;
    }

    /**
     * @param faseEstatica the faseEstatica to set
     */
    public void setFaseEstatica(Estatica faseEstatica) {
        this.faseEstatica = faseEstatica;
    }

    /**
     * @return the fase
     */
    public long getFase() {
        return fase;
    }

    /**
     * @param fase the fase to set
     */
    public void setFase(long fase) {
        this.fase = fase;
    }

    /**
     * @return the subFase
     */
    public long getSubFase() {
        return subFase;
    }

    /**
     * @param subFase the subFase to set
     */
    public void setSubFase(long subFase) {
        this.subFase = subFase;
    }

    /**
     * @return the percAvancarSubFases
     */
    public int getPercAvancarSubFases() {
        return percAvancarSubFases;
    }

    /**
     * @param percAvancarSubFases the percAvancarSubFases to set
     */
    public void setPercAvancarSubFases(int percAvancarSubFases) {
        this.percAvancarSubFases = percAvancarSubFases;
    }

    /**
     * @return the timerTransacaoImagem
     */
    public Timer getTimerTransacaoImagem() {
        return timerTransacaoImagem;
    }

    /**
     * @param timerTransacaoImagem the timerTransacaoImagem to set
     */
    public void setTimerTransacaoImagem(Timer timerTransacaoImagem) {
        this.timerTransacaoImagem = timerTransacaoImagem;
    }

    /**
     * @return the labelImagemApresentadaSubFase
     */
    public JLabel getLabelImagem() {
        return labelImagem;
    }

    /**
     *
     * @param labelImagem
     */
    public void setLabelImagem(JLabel labelImagem) {
        this.labelImagem = labelImagem;
    }

    /**
     * @return the labelStatus
     */
    public JLabel getLabelStatus() {
        return labelStatus;
    }

    /**
     * @param labelStatus the labelStatus to set
     */
    public void setLabelStatus(JLabel labelStatus) {
        this.labelStatus = labelStatus;
    }

    /**
     * @return the telaInicial
     */
    public FrameJogo getTelaInicial() {
        return telaInicial;
    }

    /**
     * @param telaInicial the telaInicial to set
     */
    public void setTelaInicial(FrameJogo telaInicial) {
        this.telaInicial = telaInicial;
    }

    /**
     * @return the tempoApresentacaoImagensApresentadasSubFase
     */
    public int getTempoApresentacaoImagens() {
        return tempoApresentacaoImagens;
    }

    /**
     * @param tempoApresentacaoImagens the
     * tempoApresentacaoImagensApresentadasSubFase to set
     */
    public void setTempoApresentacaoImagens(int tempoApresentacaoImagens) {
        this.tempoApresentacaoImagens = tempoApresentacaoImagens;
    }

    /**
     * @return the tempoTransicaoImagensApresentadasSubFase
     */
    public int getTempoTransicaoImagens() {
        return tempoTransicaoImagens;
    }

    /**
     * @param tempoTransicaoImagens the tempoTransicaoImagensApresentadasSubFase
     * to set
     */
    public void setTempoTransicaoImagens(int tempoTransicaoImagens) {
        this.tempoTransicaoImagens = tempoTransicaoImagens;
    }

    /**
     * @return the repetirApresentacaoImagensApresentadasSubFase
     */
    public int getRepetirApresentacaoImagens() {
        return repetirApresentacaoImagens;
    }

    /**
     * @param repetirApresentacaoImagens the
     * repetirApresentacaoImagensApresentadasSubFase to set
     */
    public void setRepetirApresentacaoImagens(int repetirApresentacaoImagens) {
        this.repetirApresentacaoImagens = repetirApresentacaoImagens;
    }

    /**
     * @return the apresentaMensagemAcertoErro
     */
    public boolean isApresentaMensagemAcertoErro() {
        return apresentaMensagemAcertoErro;
    }

    /**
     * @param apresentaMensagemAcertoErro the apresentaMensagemAcertoErro to set
     */
    public void setApresentaMensagemAcertoErro(boolean apresentaMensagemAcertoErro) {
        this.apresentaMensagemAcertoErro = apresentaMensagemAcertoErro;
    }

    /**
     * @return the jogoDAO
     */
    public DAOInstanciaJogo getJogoDAO() {
        return jogoDAO;
    }

    /**
     * @param jogoDAO the jogoDAO to set
     */
    public void setJogoDAO(DAOInstanciaJogo jogoDAO) {
        this.jogoDAO = jogoDAO;
    }

    /**
     * @return the modoJogo
     */
    public long getModoJogo() {
        return modoJogo;
    }

    /**
     * @param modoJogo the modoJogo to set
     */
    public void setModoJogo(long modoJogo) {
        this.modoJogo = modoJogo;
    }

    //Outros metodos
    /**
     * Inicia as subFase corretamente
     *
     * @param jogoPausado define se a apresentacao da imagem prove do pause no
     * jogo
     */
    public void iniciaFaseSubFase(boolean jogoPausado) {
        /* Retornos esperados
         0: Abre tela de mudanca de Fase/SubFase
         1: Continua apresentando imagens (pois ainda esta na mesma Fase/SubFase)
         2: Termina o jogo
         */
        switch (gerenciarFasesJogo()) {
            //Apresenta tela de troca de SubFase
            case 0:
                if (this.getFaseEstatica() != null) {
                    if (this.getSubFase() == 4 && this.getFaseEstatica().getQuantidadeImagensParaAvaliar() <= 0) {
                        this.setFase(this.getFase() + 1);
                    }
                }
                if (this.faseEstatica.buscaPorcentagemAcerto() >= this.getPercAvancarSubFases()
                        || this.modoJogo == 2
                        || this.modoJogo == 1) {
                    this.setSubFase(this.getSubFase() + 1);
                }
                this.getTelaInicial().ativarPanelTrocaFaseSubFase("Seu percentual de acerto foi: " + this.faseEstatica.buscaPorcentagemAcerto() + "%");
                this.setFaseEstatica(null); //Coloco como null pq esta subFase acabou e se iniciara outra nova
                break;
            //Jogo continua normalmente
            case 1:
                apresentarImagem(jogoPausado);
                break;
            //Jogo eh finalizado pois terminaram as 2 Fases
            default:
                this.getTelaInicial().ativarPanelFimJogo();
                break;
        }
    }

    /**
     * Faz a apresentacao das imagens, chamando o metodo da classe Estatica ou
     * da Dinamica dependendo da fase em que se encontra
     *
     * @param jogoPausado define se a apresentacao da imagem prove do pause no
     * jogo
     */
    public void apresentarImagem(boolean jogoPausado) {
        try {
            if (this.getTimerTransacaoImagem() != null) {
                this.getTimerTransacaoImagem().cancel();
            }

            //Especifica que eh uma imagem de rosto que esta sendo apresentada, pois temos imagens de acerto e erro
            //gambiarra
            labelImagem.setName("imagemRosto");

            if (this.getFase() == 1 && this.getSubFase() <= 4) {
                this.labelImagem.setIcon(null);
                this.labelImagem.repaint();

                //Enquanto existir imagens para avaliar, ira apresentar imagens
                if (this.getFaseEstatica().getQuantidadeImagensParaAvaliar() > 0) {
                    this.getFaseEstatica().apresentarImage(this, jogoPausado);
                } else {
                    iniciaFaseSubFase(false);
                }
            }

        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, VerificacaoErros.retornaMensagemErro(e), "Erro!", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Gerencia fases Estatica e Dinamica, buscando novas imagens quando
     * necessario (toda vez que mudar de Fase e/ou SubFase)
     *
     * @return Verdadeiro se o jogo nao terminou e False se o jogo terminou
     */
    public int gerenciarFasesJogo() {
        switch ((int) this.getFase()) {
            //Fase Estatica
            case 1:
                if (this.getFaseEstatica() == null) {

                    this.faseEstatica = new Estatica(this.getSubFase());
                    this.getFaseEstatica().getImagensFase().setImagens((long) (5 - this.getSubFase()) * 25, repetirApresentacaoImagens);
                    this.getFaseEstatica().setQuantidadeImagensParaAvaliar();
                    //Gravo a instancia da Fase Estatica e retorno o ID
                    if (this.modoJogo != 1) {
                        this.getFaseEstatica().setIdInstanciaSubFase(getFaseEstatica().gravaInstanciaSubFase(getIdJogo()));
                    } else {
                        this.getFaseEstatica().setIdInstanciaSubFase(-1);
                    }
                } else {
                    //Se todas imagens ja foram avaliadas
                    if (this.getFaseEstatica().getQuantidadeImagensParaAvaliar() <= 0) {
                        /*if (this.faseEstatica.buscaPorcentagemAcerto() >= this.getPercAvancarSubFases()
                         || this.modoJogo == 2
                         || this.modoJogo == 1) {
                         this.setSubFase(this.getSubFase() + 1);
                         }*/

                        return 0;
                    }
                }
                break;

            default:
                //Fim de Jogo
                System.out.println("FIM DE JOGO");
                return 2;
        }
        return 1;
    }

    /**
     * Apresenta uma imagem vazia para representar a transação de imagem
     */
    public void apresentaTransacaoImagens() {
        this.setTimerTransacaoImagem(new Timer());
        this.getTimerTransacaoImagem().schedule(new RemindTaskA(this.getTimerTransacaoImagem(), this.getTempoTransicaoImagens()), 0, 1 * 1000);
    }

    /**
     * realiza avaliacao da imagem apresentada, verifica se a fase eh estatica
     * ou dinamica para avaliar corretamente
     *
     * @param idExpressaoResposta expressao avaliada pelo jogador
     */
    public void avaliarImagem(int idExpressaoResposta) {
        String dirImagem = "./banco_de_dados/imagens_sistema/";

        labelImagem.setIcon(null);
        atualizarLabel(labelImagem);
        if (this.getFase() == 1) {
            if (this.getFaseEstatica().getTimerApresentarImagem() != null) {
                this.getFaseEstatica().getTimerApresentarImagem().cancel();
            }
            if (this.getFaseEstatica().avaliarImagemEstatica(idExpressaoResposta, this.modoJogo)) {
                //gambiarra
                dirImagem = dirImagem + "acertou1.png";
                this.getLabelImagem().setName("acertouAvaliacao");
            } else {
                //gambiarra
                dirImagem = dirImagem + "errou1.png";
                this.getLabelImagem().setName("errouAvaliacao");
            }

            if (this.isApresentaMensagemAcertoErro()) {
                ImageIcon ig = new ImageIcon(dirImagem);

                //Amplia a imagem fazendo-a ocupar todo o JLabel
                //.getScaledInstance(this.getLabelImagem().getWidth(), this.getLabelImagem().getHeight(), Image.SCALE_DEFAULT)
                this.getLabelImagem().setIcon(new ImageIcon(ig.getImage()));
                atualizarLabel(labelImagem);
            }
        }
        this.apresentaTransacaoImagens();
    }

    /**
     * Grava, no Banco de Dados, uma instancia de Jogo
     *
     * @return
     */
    public long gravaInstanciaJogo() {
        return this.getJogoDAO().gravaInstanciaJogo(this);
    }

    /**
     * Pausa jogo possibilitando
     */
    public void pausarJogo() {
        if (getFaseEstatica().getTimerApresentarImagem() != null) {
            getFaseEstatica().getTimerApresentarImagem().cancel();
        }
        if (getTimerTransacaoImagem() != null) {
            getTimerTransacaoImagem().cancel();
        }
        this.labelImagem.setIcon(null);
        this.getTelaInicial().ativarPanelJogoPausado();
    }

    public void atualizarLabel(final JLabel labelAtualizar) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                telaInicial.revalidate();
                telaInicial.repaint();
                labelAtualizar.revalidate();
                labelAtualizar.repaint();
            }
        });
    }

    class RemindTaskA extends TimerTask {

        private int segundos;
        private Timer timer = null;

        public RemindTaskA(Timer timer, int tempoEspera) {
            this.segundos = tempoEspera;
            this.timer = timer;
        }

        @Override
        public void run() {
            if (this.segundos == 0) {
                this.timer.cancel();
                timerTransacaoImagem.cancel();
                apresentarImagem(false);
            }
            segundos--;
        }
    }
}
